﻿//
// © Algobox Ltd - Benn Eichhorn
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Algobox.Apps.Finance.SterlingTrader;
using Algobox.Objects.Finance.Assets.Stock;
using Algobox.Feeds.Finance.MarketData;
using System.Threading;
using System.ComponentModel;
using Algobox.Data.Finance.AlgoboxData;
using Algobox.Objects.Finance;

namespace Algobox.Apps.Finance.SterlingQuoteRecorder
{
    public class SterlingQuoteRecorder: IDisposable, INotifyPropertyChanged
    {
        #region Constructors

        public SterlingQuoteRecorder(string connection)
        {
            PriceFeed = new QuoteAdaptor("SterlingPriceFeed");

            int count = 0;
            while(!PriceFeed.Start())
            {
                Thread.Sleep(1000);
                if (count >= MAX_APICONNECTS)
                    return;
            }

            _db = new AlgoboxDataInterface(connection);
            _timer = new System.Threading.Timer(new System.Threading.TimerCallback(UpdateData), null, 1000, 1000);
            _updateTime = DateTime.Now;
            _countMessagesPerSecond = 0;

            _db.OnBulkCollectionStatistic += new Action<int, TimeSpan>(OnBulkCollectionStatistic);
            _db.OnBulkWriteStatistic += new Action<int, TimeSpan>(OnBulkDBWriteStatistic);
            _db.OnBulkWriteFailure += new Action<string>(_db_OnBulkWriteFailure);
            _db.OnBulkCopyShutdown += new Action<string>(OnBulkCopyShutdown);
        }


        #endregion
        //////////////////
        #region Member Variables

        private int MAX_APICONNECTS = 3;

        public event PropertyChangedEventHandler PropertyChanged;
        public event Action<string> OnShutdown;

        private AlgoboxDataInterface _db;
        private System.Threading.Timer _timer;
        private long _counterMessagesTotal;
        private long _countMessagesPerSecond;
        private long _countMessagesCollected;
        private long _countMessagesWritten;
        private DateTime _updateTime;
        private TimeSpan _timeCollected;
        private TimeSpan _timeWritten;
        private string _failureMessage;

        #endregion
        //////////////////
        #region Properties
        
        public QuoteAdaptor PriceFeed { get; private set; }
        public bool IsStarted { get; private set; }
        public int NumberOfRequests { get { return PriceFeed.NumberOfSecurityRequests; } }
        public long TotalUpdates { get { return _counterMessagesTotal; } }
        public long PricesPerSecond { get { return _countMessagesPerSecond; } }
        public string UpdateTimestamp { get { return _db.BulkPriceUpdateTime.ToString("s"); } }
        public string UpdatesCollected { get { return String.Format("{0} updates collected in {1:F3}s", _countMessagesCollected, _timeCollected.TotalSeconds); } }
        public string UpdatesWritten { get { return String.Format("{0} updates written in {1:F3}s", _countMessagesWritten, _timeWritten.TotalSeconds); } }
        public string FailureMessage { get { return _failureMessage; } }
        
        #endregion
        //////////////////
        #region Functions

        public void Start()
        {
            if (!IsStarted)
            {
                List<IStock> stocks;
                if (_db.TryGetStocksFromPricesIntraday(out stocks))
                {
                    PriceFeed.OnRawQuoteUpdate += new Action<DateTime, string, Phases.Phase, double, int, bool, double, int, bool, double, int, bool>(_db.QueueQuoteUpdate);
                    foreach (IStock stock in stocks)
                    {
                        PriceFeed.SubscribeRawUpdates(stock);
                    }
                }
                IsStarted = true;
            }
        }


        void OnBulkCopyShutdown(string message)
        {
            if (OnShutdown != null)
                OnShutdown(message);
        }

        void _db_OnBulkWriteFailure(string obj)
        {
            _failureMessage = obj;
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("FailureMessage"));
            }
        }

        void OnBulkCollectionStatistic(int count, TimeSpan time)
        {
            _countMessagesCollected = count;
            _timeCollected = time;
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("UpdatesCollected"));
            }
        }

        void OnBulkDBWriteStatistic(int count, TimeSpan time)
        {
            _countMessagesWritten = count;
            _timeWritten = time;
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("UpdatesWritten"));
            }
        }

        private void UpdateData(object state)
        {
            if (_db != null)
            {
                long newCount = _db.BulkPriceTotalUpdates;
                _countMessagesPerSecond = newCount - _counterMessagesTotal;
                _counterMessagesTotal = newCount;
            }
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("PricesPerSecond"));
                PropertyChanged(this, new PropertyChangedEventArgs("UpdateTimestamp"));
                PropertyChanged(this, new PropertyChangedEventArgs("NumberOfRequests"));
                PropertyChanged(this, new PropertyChangedEventArgs("TotalUpdates"));
            }
        }

        public void Dispose()
        {
            if (_timer != null)
            {
                _timer.Dispose();
            }
            if (PriceFeed != null)
            {
                PriceFeed.Stop();
            }
            if (_db != null)
            {
                _db.Dispose();
                _db = null;
            }
        }
        
        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
        //////////////////
        #region Enums



        #endregion
    }
}
